import pandas as pd
df = pd.read_csv('https://query.data.world/s/guh6xsutvf7cz5iajnygsf6c64nf6s')
df
df.describe()
#imprimiendo la primer parte del dataset
df.head()
#imprimiendo la ultima parte del dataset
df.tail()
#maximo id de un taxista en la app --> posible cantidad de taxistas, aunque puede que hayan agujeros en el medio
df['id_taxista_r'].max()
#minimo id de un taxista en la app
df['id_taxista_r'].min()
#hago el count de id únicos --> al final me da igual que el maximo, son 1215 taxistas
df['id_taxista_r'].nunique()
print('Tengo', df['id_taxista_r'].nunique(), 'taxistas que están usando la app en este período')
from IPython.display import HTML # --> importo HTML para poder usar bold
HTML("Hay <b>" + str(df['id_taxista_r'].nunique()) + "</b> taxistas que usan la app BATaxi en este período")
#busco el período que se está teniendo en cuenta en el dataset
#agarro el mínimo de las fechas de inicio y el máximo de las fechas de fin
#tomo los caracteres del 0 al 10 para que me muestre solo la fecha y no la hora
[df['fecha_inicio'].min()[0:10], df['fecha_fin'].max()[0:10]]
#veo el tipo de dato de cada atributo
df.dtypes
#reduzco el tamaño de "cantidad de pasajeros" a un int8 para que ocupe menos memoria
import numpy as np
df = df.astype({"cantidad_pasajeros": np.int8})
#veo el uso de memoria, cantidad de pasajeros ocupa menos que antes (19148 vs 153184)
df.memory_usage()
#agrego una columna con el mes del viaje segun la fecha de inicio
df["mes"] = pd.DatetimeIndex(df['fecha_inicio']).month
df.head()
#si quiero borrar una columna de la tabla (habia agregado la columna month pero los nombres estan en español) uso "del df['month']"
#agrupo por mes y cuento la cantidad de viajes por mes (como Series)
#https://stackoverflow.com/questions/19384532/get-statistics-for-each-group-such-as-count-mean-etc-using-pandas-groupby (segunda respuesta)
df.groupby(['mes']).size()
#lo mismo pero como DataFrame
df.groupby(['mes']).size().reset_index(name='count')
#si hago esto es raro porque para todas las columnas me da la el count de viajes (registros)
df.groupby('mes').count()
#defino cant para no usar los atributos del dataset como si hiciera df[['month', 'id_viaje_r']].groupby('month').count()
df['cant'] = 1
df[['mes', 'cant']].groupby('mes').count()
#importo altair para hacer gráficos
import altair as alt
#guardo la consulta en source1
source1 = df.groupby(['mes']).size().reset_index(name='count')
#hago un gráfico con source1
alt.Chart(source1).mark_bar().encode(
x='mes',
y='count'
).properties(width=200).mark_bar(size=25)
#guardo la consulta en source
source = df[['mes', 'cant']].groupby('mes').count().reset_index()
#hago un gráfico con el código del profe
alt.Chart(source).mark_bar().encode(
x='mes:O', #le pido que mes sea ordinal para que no me lo muestre con coma
y='cant'
).properties(width=200).mark_bar(size=25) #properties es para el ancho del gráfico, mark_bar para el ancho de las columnas
#transpongo el gráfico y le agrego labels a las barras
bars = alt.Chart(source).mark_bar().encode(
x='cant',
y='mes:O' #cambio las variables de lugar para transponer
).properties(
width=450,
height=150
).mark_bar(size=25)
text = bars.mark_text(
align='left',
baseline='middle',
dx=3 #mueve el texto un poco a la derecha para que no se superponga con la barra
).encode(
text='cant'
)
(bars + text) #muestro el gráfico
#instalo para calcular distancias
!pip install geopy
#calculo la distancia de los viajes segun las coordenadas de origen y destino y la agrego a la columna distancia
from geopy.point import Point
from geopy.distance import geodesic
df['distancia'] = df.apply(lambda dato: int(geodesic(
Point(latitude=dato['origen_viaje_y'], longitude=dato['origen_viaje_x']) ,
Point(latitude=dato['destino_viaje_y'], longitude=dato['destino_viaje_x'])).meters),
axis=1)
df.head()
#importo una función para calcular la distancia entre dos coordenadas de otra forma
import math
def distance(origin, destination):
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km
dlat = math.radians(lat2-lat1)
dlon = math.radians(lon2-lon1)
a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(lat1)) \
* math.cos(math.radians(lat2)) * math.sin(dlon/2) * math.sin(dlon/2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
d = radius * c
return d
#agrego una columna distancia2 calculando distancias con la nueva fórmula (va a dar apenas distinto)
df['distancia2'] = df.apply(lambda d: int(1000*distance(
(d['origen_viaje_y'], d['origen_viaje_x']) ,
(d['destino_viaje_y'], d['destino_viaje_x']))),
axis=1)
df.head()
#histogramas de la duracion y la distancia, con pandas
hist = df[['distancia', 'duracion']].hist()
#histograma de la distancia, con altair
#le pido que lea todas las rows por más que sean más de 5000
alt.data_transformers.disable_max_rows()
alt.Chart(df).mark_bar().encode(
alt.X("distancia:Q", bin=True),
y='count()',
)
#histograma de la duracion, con altair
alt.Chart(df).mark_bar().encode(
alt.X("duracion:Q", bin=True),
y='count()',
)
#calculo la hora de inicio de los viajes para ver horas de mayor demanda, y lo agrego la columna hour
df["hour"] = pd.DatetimeIndex(df['fecha_inicio']).hour
df.head()
df.tail()
#hago un gráfico del count de viajes en cada hora para ver las horas de mayor demanda
alt.Chart(df).mark_line().encode(
x='hour',
y='count()'
)
hist1 = alt.Chart( df ).mark_bar().encode(
alt.X("distancia:Q", bin=True),
y='count()',
)
hist2 = alt.Chart( df ).mark_bar().encode(
alt.X("duracion:Q", bin=True),
y='count()',
)
# alt.hconcat(hist1, hist2)
# o
hist1 | hist2
import pandas as pd
df = pd.read_csv('https://query.data.world/s/guh6xsutvf7cz5iajnygsf6c64nf6s')
import altair as alt
df.head()
Veamos cómo evoluciona la cantidad de taxistas registrados mes a mes.
Primero agrego el atributo 'mes' al dataset.
df['mes'] = pd.DatetimeIndex(df['fecha_inicio']).month
df[['fecha_inicio','mes']]
Ahora calculo cuántos ids de taxistas distintos hay en cada mes.
source = df.groupby(['mes']).id_taxista_r.nunique().reset_index(name='count')
source
Vemos que la cantidad de taxistas registrados va aumentando mes a mes, lo cual sugiere que la app aumentó su popularidad.
Muestro el aumento en gráficos. Primero usando Altair.
alt.Chart(source).mark_bar().encode(
x=alt.X('mes:O', title='Mes', axis=alt.Axis(labelAngle=0)),
y=alt.Y('count', title='Cantidad de taxistas registrados')
).properties(width=300).mark_bar(size=30)
Ahora usando Pandas.
chart = source.plot.bar(x='mes',y='count',rot=0, legend=False)
chart.set_xlabel('Mes')
chart.set_ylabel('Número de taxistas registrados')
chart.set_xticklabels(chart.get_xticklabels(), rotation=0);
Ahora analicemos los días de la semana con más viajes.
Primero agrego una columna con el día de la semana correspondiente a cada viaje.
df['dia_de_la_semana'] = pd.DatetimeIndex(df['fecha_inicio']).dayofweek
df[['fecha_inicio','dia_de_la_semana']].head(200)
Luego agrupo por día de la semana y hago un count para contar los viajes de cada día.
source2 = df.groupby(['dia_de_la_semana']).id_viaje_r.nunique().reset_index(name='count')
source2['dia_de_la_semana_nombre'] = ['Lunes','Martes','Miércoles','Jueves','Viernes','Sábado','Domingo']
source2
Vemos que hacia el fin de semana la demanda de taxis aumenta.
Ahora grafico la cantidad de viajes por día. Primero usando Altair.
alt.Chart(source2).mark_line(clip=True).encode(
x=alt.X('dia_de_la_semana_nombre',
title='Dia de la semana',
sort=alt.EncodingSortField(field="dia_de_la_semana", order='ascending'),
axis=alt.Axis(labelAngle=0)),
y=alt.Y('count', title='Cantidad de viajes', scale=alt.Scale(domain=(2000, 3500)))
).properties(width=400)
Ahora usando Pandas.
chart = source2.plot.line(x='dia_de_la_semana_nombre',y='count',rot=0, legend=False)
chart.set_xlabel('Día de la semana')
chart.set_ylabel('Número de viajes')
chart.set_xticklabels(chart.get_xticklabels(), rotation=0);
Ahora veamos a qué horas se hacen viajes más largos.
Primero agrego la columna hora al DataFrame, teniendo en cuenta la hora de partida.
df['hora'] = pd.DatetimeIndex(df['fecha_inicio']).hour
df[['fecha_inicio','hora']].head(100)
También agrego una columna donde calculo la duración de los viajes en minutos en vez de segundos.
df['duracion_en_minutos'] = df['duracion'].div(60)
df[['duracion','duracion_en_minutos']].head()
Ahora agrupo por hora y saco la duración promedio de los viajes para cada hora.
source3 = df.groupby(['hora'])['duracion_en_minutos'].mean().reset_index(name='duracion_promedio')
source3
Vemos que la duración promedio de los viajes es similar a toda hora, con un máximo a las 5am y un mínimo a las 11pm.
Grafico la duración promedio de viaje para cada hora. La linea roja representa la duración promedio de viaje a toda hora.
grafico = alt.Chart(source3).mark_line(clip=True).encode(
x=alt.X('hora',
title='Hora',
axis=alt.Axis(labelAngle=0),
scale=alt.Scale(domain=(0, 23))),
y=alt.Y('duracion_promedio',
title='Duración promedio de viaje en minutos',
scale=alt.Scale(domain=(14, 18)))
).properties(width=400)
rule = alt.Chart(source3).mark_rule(color='red').encode(
y='mean(duracion_promedio):Q'
)
grafico + rule
prom = source3['duracion_promedio'].mean()
print('Duración promedio de viaje:', round(prom, 2), 'minutos')
Vemos que la duración promedio de viaje es de 15.57 minutos
Ahora analizo si hay taxistas que suelen hacer viajes más largos que otros.
Primero agrupo por id de taxista y calculo la duración promedio de sus viajes.
source4 = df.groupby(['id_taxista_r'])['duracion_en_minutos'].mean().reset_index(name='duracion_promedio')
source4
Graficamos la información para ver si hay taxistas con promedio de viaje notoriamente mayor.
alt.Chart(source4).mark_bar(clip=True).encode(
x=alt.X('id_taxista_r',
title='ID del taxista',
axis=alt.Axis(labelAngle=0),
scale=alt.Scale(domain=(0, 1250))),
y=alt.Y('duracion_promedio',
title='Duración promedio de viaje en minutos')
).properties(width=1000).mark_bar(size=1.5)
Vemos que hay algunos taxistas que se destacan por hacer viajes largos.
Obtengo los 10 taxistas con promedio de viaje más largo.
source4.nlargest(10,'duracion_promedio')
Vemos que 6 taxistas tienen un promedio de viaje de más de media hora.
Ahora veamos los 10 promedios de viaje más cortos.
source4.nsmallest(10,'duracion_promedio')
Vemos que hay 8 taxistas que suelen hacer viajes de menos de 4 minutos.
Ahora analicemos la cantidad de pasajeros en los viajes. En primer lugar veamos las frecuencias para el número de pasajeros.
alt.data_transformers.disable_max_rows()
alt.Chart(df).mark_bar().encode(
alt.X("cantidad_pasajeros:Q",
title='Cantidad de pasajeros',
axis=alt.Axis(labelAngle=0),
bin=alt.Bin(extent=[1, 5], step=1)),
alt.Y('count()', title='Cantidad de viajes'),
).properties(width=200).mark_bar(size=49)
Vemos que más de la mitad de los viajes son de 1 pasajero, seguidos por los de 2, luego los de 3, y por último los de 4.
Ahora veamos si los viajes de más pasajeros suelen ser más largos o no. Primero agrego la columna distancia al DataFrame.
from geopy.point import Point
from geopy.distance import geodesic
df['distancia'] = df.apply(lambda dato: int(geodesic(
Point(latitude=dato['origen_viaje_y'], longitude=dato['origen_viaje_x']) ,
Point(latitude=dato['destino_viaje_y'], longitude=dato['destino_viaje_x'])).meters),
axis=1).div(1000)
df[['distancia']].head(100)
Ahora calculo la distancia promedio para las distintas cantidades de pasajeros.
source5 = df.groupby(['cantidad_pasajeros'])['distancia'].mean().reset_index(name='distancia_promedio')
source5
Vemos que, al parecer, un mayor número de pasajeros no significa viajes más largos (con el objetivo de ahorrar dinero).
Graficamos los resultados obtenidos.
alt.Chart(source5).mark_bar().encode(
x=alt.X('cantidad_pasajeros:O', title='Cantidad de pasajeros', axis=alt.Axis(labelAngle=0)),
y=alt.Y('distancia_promedio', title='Distancia promedio del viaje en km')
).properties(width=300).mark_bar(size=30)
Por último, analicemos si un mayor tiempo de viaje significa una mayor distancia recorrida.
Primero extraigo los datos que me interesan del DataFrame.
source6 = df[['duracion_en_minutos','distancia']]
source6
Luego grafico en un scatter plot. Calculo la regresión lineal.
scatterplot = alt.Chart(source6).mark_point(size=30).encode(
x=alt.X('duracion_en_minutos:Q', title='Duración del viaje en minutos', axis=alt.Axis(labelAngle=0)),
y=alt.Y('distancia', title='Distancia del viaje en km',scale=alt.Scale(domain=(0, 40)))
).properties(width=500)
regression = scatterplot.transform_regression('duracion_en_minutos', 'distancia',method="linear"
).mark_line(color="red")
scatterplot + regression
Vemos que en lineas generales, a mayor duración del viaje, mayor es la distancia que se recorre. De todos modos, esto no siempre es así y vemos valores outliers que muestran que para viajes largos se recorrió muy poca o demasiada distancia. El primer caso puede deberse a factores como el tráfico, que hacen que un viaje de corta distancia tarde más en realizarse. El segundo puede deberse a la utilización de medios como autopistas, que permiten recorrer más distancia en menor tiempo dado que la velocidad máxima permitida es mayo.